Copyright ã1995 by NeXT Computer, Inc.  All Rights Reserved.

IXRecordManager

Inherits From:	Object

Conforms To:	IXBlockAndStoreAccess
IXNameAndFileAccess
IXRecordWriting
IXTransientAccess
IXTransientMessaging

Declared In:	indexing/IXRecordManager.h

Class Description

IXRecordManager is a record manager based on the Objective C run-time system; it stores objects in an IXStore, and maintains indexes on programmer-defined attributes.  Attributes are defined in terms of the return values of messages sent to the stored objects.  The stored objects can be retrieved by persistent identifiers, by their attribute values, or by posing a question with IXAttributeQuery, a class that defines a declarative query language for IXRecordManager and other Indexing Kit classes.

Storing Records

IXRecordManager archives, or passivates, an object by writing its data into an IXBTree record.  Two archiving mechanisms are provided: Objective C archiving, as performed by the standard read: and write: methods, and serialization, a very fast transcription mechanism that writes or reads an object's instance variables directly into or out of storage.  An object will be serialized instead of archived if it conforms to the IXRecordTranscription protocol.  For the purpose of serialization, a data type can be serialized if its length can be unambiguously determined from its type declaration and its physical representation; this includes all scalar ANSI C data types, pointers to character strings (which are assumed to be null-terminated), and fixed length arrays of the preceding kinds of data types.

IXRecordManager defines a mechanism for storing and retrieving amorphous data items, called blobs, that aren't susceptible to structural serialization due to unknown length or complexity.  Some examples of blobs are compressed sounds, serialized graph structures, and relocatable code modules.  Before serializing an object that conforms to the IXRecordTranscription protocol, IXRecordManager sends it a source:willWriteRecord: message, giving the object an opportunity to prepare itself for passivation, or to request the IXRecordManager to write its unserializable data as blobs.  When a record is deserialized, or activated, the IXRecordManager sends source:didReadRecord: to it.

Blobs are identified by name and record handle.  This provides a means of maintaining lists of named properties on behalf of transcribed records.  There is no way of iterating over the property names or of getting a list of all blob names for an object, so objects should store their own such lists in a well-known blob if the list membership can't be determined statically.

The IXRecordManager interface allows a record to be added, discarded, removed, or replaced by another record.  Discarded records are treated as though they don't existÐthey can't be read, for example.  They will either be physically removed when the repository is cleaned, or explicitly reclaimed by the caller.  The facility for discarding records is designed to support lazy index maintenance; references to discarded records may safely be allowed to remain in the inversions until the repository is cleaned.  Record discarding also provides a form of disaster recovery when add and discard operations are used instead of replacement.

Indexing Records

IXRecordManager allows attributes to be defined by name and method, such as ªEmployeeNameº with the method given by @selector(empName).  The value of an attribute for a given record is the value returned when the attribute's message is sent to that record.  If a record doesn't respond to the message, then the attribute isn't defined for that record.  By default, an attribute is defined for every record that responds to its message; its scope may be further restricted to those records that are instances of a specific class or subclasses of that class.

Here's an example of setting up an attribute for employees by full name (with a method empName that returns a character string), and restricting it to instances of MyEmployeeRecord and its subclasses:

[recordManager addAttributeNamed:"EmployeeName"
    forSelector:@selector(empName)];
[recordManager setTargetClass:[MyEmployeeRecord class]
    forAttributeNamed:"EmployeeName"];

IXRecordManager maintains an index for each of its attributes; the index is an inversion of the attribute's value over all of the records for which it's defined.  An attribute index is an IXBTree managed by an IXPostingCursor; IXRecordManager determines the comparator for the IXBTree by examining the return type of the attribute's selector.  The default comparator can be overridden (as would be necessary for methods that returned structures or unions) with the setComparator:andContext:forAttributeNamed: or setComparisonFormat:andContext:forAttributeNamed: methods.  In the example given above, the default comparator would be IXCompareStrings, since empName is defined as returning a string. For more information on comparators, see the IXComparatorSetting and IXComparisonSetting protocol specifications.

The IXAttributeParser class can be used to index string-valued attributes under each of the separate lexemes (words or other useful units of text) in a string, instead of using the entire string as the value.  The setParser:forAttributeNamed: message assigns a parser that will break the selector's return value into its constituent words.  If the attribute in the example above were based on a method that returns a text string containing unstructured, miscellaneous notes, then assigning a parser might be appropriate.  Using the default parser configuration for English, an employee record with the note ªHas three kids named Bobby, Judy and Samº would be recorded in the index under the values ªHas,º ªthree,º ªkid,º ªnamed,º ªBobby,º ªJudy,º and ªSam.º  Note that ªand,º being considered a noise word in English, isn't included, and that the plural ªkidsº was reduced to ªkid.º  See the IXAttributeParser and IXAttributeReader class specifications for more information on parsers.

Retrieving Records

References to records are stored as postings in the attribute indexes.  A posting is a reference identifier plus its weight (a measure of its frequency or importance in the index). Any index can be examined through an IXPostingCursor returned by cursorForAttributeNamed:.  A new copy of the cursor is returned for each invocation of this method, so the sender should free each copy when it's no longer needed.  The basic cursoring techniques described in the IXCursorPositioning protocol specification can be used to locate references to all of the records having a given value for the attribute, or to iterate over the set of existing values for the attribute.  As described in the IXPostingSet class specification, an IXPostingSet can be used to retrieve sets of postings directly from the IXPostingCursor, and can combine those sets in various ways.  References to records for a range of attribute values can  be collected using one IXPostingCursor and one IXPostingSet.  See the IXPostingSet class specification for an example.

IXPostingSets built against different attributes can be combined to resolve multi-attribute queries.  For example, all employees with a last name of ªDraperº and a salary of at least $60,000 could be found by collecting the appropriate postings from the EmployeeName and Salary attributes into two separate IXPostingSets, and intersecting the results.  Another Indexing Kit class, IXAttributeQuery, resolves declarative queries expressed in a functional  language against instances of IXRecordManager and other classes using these techniques.

Instance Variables

None declared in this class.

Adopted Protocols

IXBlockAndStoreAccess	- initInStore:
- initFromBlock:inStore:
- freeFromStore
+ freeFromBlock:inStore:
- getBlock:andStore:

IXNameAndFileAccess	- initWithName:inFile:
- initFromName:inFile:
- freeFromStore
+ freeFromName:inFile:
- getName:andFile:

IXRecordWriting	- addRecord:
- removeRecord:
- replaceRecord:with:
- empty
- count
- readRecord:fromZone:

IXTransientAccess	- getOpaqueValue:ofIvar:forRecord:
- getIntValue:ofIvar:forRecord:
- getFloatValue:ofIvar:forRecord:
- getDoubleValue:ofIvar:forRecord:
- getStringValue:ofIvar:forRecord:
- getStringValue:inLength:ofIvar:forRecord:
- getObjectValue:ofIvar:forRecord:

IXTransientMessaging	- getOpaqueValue:ofMessage:forRecord:
- getIntValue:ofMessage:forRecord:
- getFloatValue:ofMessage:forRecord:
- getDoubleValue:ofMessage:forRecord:
- getStringValue:ofMessage:forRecord:
- getStringValue:inMessage:ofIvar:forRecord:
- getObjectValue:ofMessage:forRecord:

Method Types

Adding and removing attributes	- addAttributeNamed:forSelector:
- hasAttributeNamed:
- removeAttributeNamed:
- attributeCount

Key comparison	- setComparisonFormat:forAttributeNamed:
- comparisonFormatForAttributeNamed:
- setComparator:andContext:forAttributeNamed:
- getComparator:andContext:forAttributeNamed:

Setting attribute targets	- setTargetClass:forAttributeNamed:
- getTargetName:andVersion:forAttributeNamed:

Accessing attributes	- cursorForAttributeNamed:

Getting attribute information	- selectorForAttributeNamed:
- attributeNames

Accessing classes	- classNames
- attributeNamesForClass:
- recordsForClass:

Discarding records	- discardRecord:
- reclaimRecord:
- discards
- clean

Setting attribute descriptions	- setDescription:forAttributeNamed:
- getDescription:forAttributeNamed:

Setting parsers	- setParser:forAttributeNamed:
- parserForAttributeNamed:

Writing blobs	- setValue:andLength:ofBlob:forRecord:
- getValue:andLength:ofBlob:forRecord:

Instance Methods

addAttributeNamed:forSelector:

- addAttributeNamed:(const char *)aName forSelector:(SEL)aSelector

Creates an attribute for records that respond to aSelector, associates it with name aName, and builds an index for that attribute.  Note that records already passivated by the IXRecordManager that respond to aSelector are not added to the new index automatically.  This may change in a future release.  If an attribute already exists with name aName, returns nil; otherwise returns non-nil.

See also:  - removeAttributeNamed:, - selectorForAttributeNamed:

attributeCount

- (unsigned int)attributeCount

Returns the number attributes defined for the IXRecordManager.

See also:  - count

attributeNames

- (char *)attributeNames

Returns a newline-separated list of the names of all attributes in the IXRecordManager.  The sender of this message is responsible for freeing the string returned.

See also:  - addAttributeNamed:forSelector:

attributeNamesForClass:

- (char *)attributeNamesForClass:aClass

Returns a newline-separated list of the names of all of the attributes maintained by the IXRecordManager that are defined for instances of aClass.  This includes all of the attributes whose selectors are recognized by instances of aClass, and whose target class is aClass or one of its superclasses.  The sender of this message is responsible for freeing the string returned.

See also:  - setTargetClass:forAttributeNamed:

classNames

- (char *)classNames

Returns a newline-separated list of the names of all the classes that have instances stored in the IXRecordManager.  The sender of this message is responsible for freeing the string returned.

clean

- clean

Removes all discarded records from the receiver.  Those records will no longer be reclaimable.  Returns self.

See also:  - discardRecord:, - reclaimRecord:, - empty (IXRecordReading protocol)

comparisonFormatForAttributeNamed:

- (const char *)comparisonFormatForAttributeNamed:(const char *)aName

Returns a string defining the comparison format of keys in the index named aName, or NULL if one hasn't been set.  This is a string encoding the Objective C data types that comprise the key; for example, ª[3i]º describes an array of 3 integers.  An IXBTree uses this format to determine how to compare keys.  For more information on comparison formats, see the IXComparisonSetting protocol specification.

See also:  - setComparisonFormat:forAttributeNamed:, - getComparator:andContext:forAttributeNamed:

count

- (unsigned int)count

Returns the number of records stored in the IXRecordManager, plus the number of attributes defined.  To get just the number of records, subtract the return value of attributeCount from the return value of this method.

See also:  - attributeCount, - count (IXRecordWriting protocol)

cursorForAttributeNamed:

- (IXPostingCursor *)cursorForAttributeNamed:(const char *)aName

Returns an IXPostingCursor that addresses the index for the attribute named aName.  This cursor can be used to find references to records having a given value for the attribute.  For more information on using cursors, see the IXCursorPositioning protocol specification, and the IXPostingCursor class specification.

This method returns a copy of a private cursor each time it's invoked, so your code should free the copy when it's no longer needed.

discardRecord:

- discardRecord:(unsigned int)aHandle

Discards the record identified by aHandle, so that the record can't be read, removed or replaced.  reclaimRecord: retrieves discarded records, and clean removes all discarded records.  Returns self.

See also:  - reclaimRecord:, - clean, - discards, - removeRecord: (IXRecordWriting)

discards

- (IXPostingList *)discards

Returns an IXPostingList containing all records that have been discarded (by sending discardRecord: to the IXRecordManager).  This IXPostingList can be used to reclaim the discarded records with reclaimRecord:.

If the IXRecordManager is asked to read a discarded record (with the IXRecordReading protocol's readRecord:FromZone: method), the result will be nil; for most purposes the record no longer exists.  However, discarded records will still have references in the IXRecordManager's attribute indexes.  If your code doesn't deal gracefully with nil records, you can filter posting sets before using them by subtracting the discards from them.

See also:  - discardRecord:, - reclaimRecord:, - clean

getComparator:andContext:forAttributeNamed:

- getComparator:(IXComparator **)aComparator
andContext:(const void **)aContext
forAttributeNamed:(const char *)aName

Returns by reference the function used to compare attribute values, and the context associated with that function, for the attribute named aName.  If the attribute has a comparison format set instead, the comparator and context will be NULL.  A comparator function takes two data items and returns an answer indicating whether the first is less than, equal to, or greater than the second.  The context is arbitrary data for use by that function.  Returns self.

For more information on comparators, see the IXComparatorSetting protocol specification and the IXBTree class specification.

See also:  - setComparator:andContext:forAttributeNamed:, - comparisonFormat:forAttributeNamed:

getDescription:forAttributeNamed:

- getDescription:(char **)aDescription forAttributeNamed:(const char *)aName

Returns by reference the description for the attribute named aName.  The description can be used to record extra information pertaining to the attribute.  Returns self.

See also:  - setDescription:forAttributeNamed:, - addAttributeNamed:forSelector:

getTargetName:andVersion:forAttributeNamed:

- getTargetName:(const char **)aName
andVersion:(unsigned int *)targetVersion
forAttributeNamed:(const char *)aName

Returns by reference the name and version of the class that the attribute named aName is defined for, or NULL and 0 if none has been set.  If an attribute has a target class set, it will be defined only for records of that class or a subclass.  Returns self.

See also:  - setTargetClass:forAttributeNamed:

getValue:andLength:ofBlob:forRecord:

- (BOOL)getValue:(void **)aValue
andLength:(unsigned int *)aLength
ofBlob:(const char *)blobName
forRecord:(unsigned int)aHandle

Returns by reference the value and length of blobName for the record identified by aHandle.  Returns YES if the blob is successfully retrieved, NO if it isn't.

Note:  Your application should use the NXSwapBigTypeToHost() function to convert the byte-order of the retrieved blob data to that of the machine it's running on.

See also:  - setValue:andLength:ofBlob:forRecord:

hasAttributeNamed:

- (BOOL)hasAttributeNamed:(const char *)aName

Returns YES if the IXRecordManager has an attribute named aName, NO if it doesn't.

parserForAttributeNamed:

- (IXAttributeParser *)parserForAttributeNamed:(const char *)aName

Returns the parser, if any, assigned to the attribute named aName.  The parser will break the return value of the attribute's selector into separate words when the attribute is evaluated.

See also:  - setParser:forAttributeNamed:

reclaimRecord:

- reclaimRecord:(unsigned int)aHandle

Reclaims a record previously discarded with discardRecord:.  aHandle is the identifier of the discarded record.  A discarded record must be reclaimed in order to access it or remove it completely from the archive (although clean removes all discarded records at once).  Returns self.

See also:  - discardRecord:, - discards, - clean

recordsForClass:

- (IXPostingList *)recordsForClass:aClass

Returns an IXPostingList containing all of the records in the IXRecordManager that are direct instances of aClass (and not of any subclasses of aClass).

removeAttributeNamed:

- removeAttributeNamed:(const char *)aName

Removes the attribute named aName from the IXRecordManager.  Records referenced by the attribute's index aren't affected.  Returns self.

See also:  - addAttributeNamed:forSelector:

selectorForAttributeNamed:

- (SEL)selectorForAttributeNamed:(const char *)aName

Returns the selector for the message that defines the attribute named aName.  Unless the attribute is restricted to a specific class, this message is sent to any record that responds to it in order to evaluate the attribute.  Otherwise it's only sent to records of the attribute's target class (or a subclass of the target class).

See also:  - addAttributeNamed:forSelector:

setComparator:andContext:forAttributeNamed:

- setComparator:(IXComparator *)aComparator
andContext:(const void *)aContext
forAttributeNamed:(const char *)aName

Sets the function used to compare attribute values, and the context associated with that function, for the attribute named aName.  A comparator function should accept two data items and return an answer indicating whether the first is less than, equal to, or greater than the second.  The context is arbitrary data for use by that function.  Returns self.

For more information on comparators, see the IXComparatorSetting protocol specification and the IXBTree class specification.

See also:  - getComparator:andContext:forAttributeNamed:, - setComparisonFormat:forAttributeNamed:

 setComparisonFormat:forAttributeNamed:

- setComparisonFormat:(const char *)aFormat forAttributeNamed:(const char *)aName

Installs a string defining the comparison format of keys in the index named aName.  This is a string encoding the Objective C data types that comprise the key; for example, ª[3i]º describes an array of 3 integers (although the length is currently ignored).  An IXBTree uses this format to determine how to compare keys.  For more information on comparison formats, see the IXComparisonSetting protocol specification.

See also:  - comparisonFormat:forAttributeNamed:, - setComparator:andContext:forAttributeNamed:

setDescription:forAttributeNamed:

- setDescription:(const char *)aDescription forAttributeNamed:(const char *)aName

Sets the description for the attribute named aName to aDescription.  The description can be used to record extra information pertaining to the attribute.  Returns self.

See also:  - getDescription:forAttributeNamed:

setParser:forAttributeNamed:

- setParser:(IXAttributeParser *)aParser forAttributeNamed:(const char *)aName

Assigns the parser aParser to the attribute named aName.  The parser will break the return value of the attribute's selector into separate words when the attribute is evaluated.  Returns self.

See also:  - parserForAttributeNamed:

setTargetClass:forAttributeNamed:

- setTargetClass:aClass forAttributeNamed:(const char *)aName

Sets the target class for the attribute named aName to aClass.  The attribute will be defined only for instances of class aClass or any of its subclasses.  Your code should set the target class before any records have been added to the IXRecordManager; otherwise, the index for the named attribute may collect references to instances of other classes before the restriction is imposed.  This behavior may change in a future release, so that records that aren't of aClass are removed from the index when the target class is set.  Returns self.

See also:  - getTargetName:andVersion:forAttributeNamed:

setValue:andLength:ofBlob:forRecord:

- (BOOL)setValue:(const void *)aValue
andLength:(unsigned int)aLength
ofBlob:(const char *)blobName
forRecord:(unsigned int)aHandle

Stores the value and length of a blob for the record identified by aHandle, associating it with the name blobName.  Returns YES if the blob is successfully stored, NO if it wasn't.

If aLength is 0, the blob won't be stored, and this method will return NO.

Note:  Your application should use the NXSwapHostTypeToBig() function before invoking this method, to convert the byte-order of the key to big-endian (the standard byte-order for the Indexing Kit).

See also:  - getValue:andLength:ofBlob:forRecord: